package pattern;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;


/** 
 * A class to capture console IO. Be sure to stop capturing in time, to get faster read-operations.<br>
 * It's not tested for longer capturing or capturing massive Output.
 * @author martin.lemanski
 *
 */
public class SystemOutCapturer {
	private ByteArrayOutputStream byteArrayOutputStream;
	private PrintStream originalOutputStream;

	/**
	 * Constructor remembers original Output Stream of System.out.
	 */
	public SystemOutCapturer() {
		byteArrayOutputStream = new ByteArrayOutputStream();
		originalOutputStream = System.out;
	}

	
	/**
	 * Start the capturing.
	 */
	public void startCapturingConsole() {
		System.setOut(new PrintStream(byteArrayOutputStream));
	}

	/**
	 * Reads only the first line of whole Capture
	 * @return String - first line
	 * @throws IOException
	 */
	public String readLine() throws IOException {
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())));
		return bufferedReader.readLine();
	}

	/**
	 * Reads line at lineNumber
	 * @param lineNumber
	 * @return String - line from lineNumber
	 * @throws IOException
	 */
	public String readLine(int lineNumber) throws IOException {
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())));
		for(int i = 1; i < lineNumber; i++) {
			bufferedReader.readLine();
		}
		return bufferedReader.readLine();
	}

	/**
	 * This input stream is just a snapshot of the expected console-output from start of capturing until.
	 * @return
	 */
	@Deprecated
	public ByteArrayInputStream getByteArrayInputStream() {
		return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
	}

	/**
	 * Ends the capturing, reverts the System.out stream to it's default and returns a list of lines.
	 * @return List<String> A list of strings
	 * @throws IOException
	 */
	public List<String> stopCapturingConsole() throws IOException {
		originalOutputStream.write(byteArrayOutputStream.toByteArray());
		System.setOut(originalOutputStream);
		return getLinesAsList();
	}

	/**
	 * 
	 * @return List<String> A list of lines
	 * @throws IOException
	 */
	public List<String> getLinesAsList() throws IOException {
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())));
		List<String> stringList = new ArrayList<String>();
		String line;
		while((line = bufferedReader.readLine()) != null)
			stringList.add(line);
		return stringList;
	}

}
